import java.util.ArrayList;
import java.util.HashMap;

public class TabelaRotas {

	static final int INFINITY = 999;
	private Router roteador;
	private VetorDistancia vetorDistancia;
	private HashMap<Integer, VetorDistancia> vectors;

	public TabelaRotas(Router roteador) {
		this.roteador = roteador;
		this.vetorDistancia = new VetorDistancia(roteador.getId());
		vectors = new HashMap<Integer, VetorDistancia>();
	}

	public void inicializar() {
		ArrayList<Neighbor> roteadores = roteador.getNeighbors();

		for (Neighbor idNo : roteadores) {
			if (roteador.getId().compareTo(idNo.getId()) == 0) {
				vetorDistancia.put(idNo.getId(), new Custo(0, idNo.getId()));
			} else if (idNo.isNeighbor() && roteador.isConnected(idNo.getId())) {
				vetorDistancia.put(idNo.getId(), new Custo(idNo.getCost(), idNo.getId()));
			} else {
				vetorDistancia.put(idNo.getId(), new Custo(INFINITY, idNo.getId()));
			}
		}
	}

	public void atualizarRotas(VetorDistancia vetorD) {
		int idNovo = vetorD.getId();
		int indexOf = roteador.getNeighbors().indexOf(new Neighbor(idNovo, 0, false));
		int vizinhoCusto = roteador.getNeighbors().get(indexOf).getCost();

		if(vetorDistancia.get(idNovo).getCusto() > vizinhoCusto){
			int custo = roteador.getNeighbors().get(indexOf).getCost();
			vetorDistancia.get(idNovo).setCusto(custo);
			vetorDistancia.get(idNovo).setId(idNovo);
		}
		
		if (!getVectors().containsKey(vetorD.getId())) {
			System.out.println("connecting: " + vetorD.getId());
			getVectors().put(vetorD.getId(), vetorD);
			atualizaVectorConectado(vetorD.getId());
			return;
		}

		if (!getVectors().get(vetorD.getId()).equals(vetorD)) {
			System.out.println("updating: " + vetorD.getId());
			getVectors().put(vetorD.getId(), vetorD);
			atualizaVectorConectado(vetorD.getId());
			return;
		}
		
		System.out.println(vetorDistancia.toString());
	}

	private void atualizaVectorConectado(int id) {
		//novo vetor fornecido.
		VetorDistancia vDist = this.vectors.get(id);
		VetorDistancia myDist = this.vetorDistancia;
		Custo cEnlase = this.vetorDistancia.get(id);
		
		for (Integer key : myDist.getVetor().keySet()) {
			Custo myCusto = myDist.get(key);
			if (myCusto.getCusto() >= cEnlase.getCusto() + vDist.get(key).getCusto() || myDist.get(key).getId() == id) {
				myDist.get(key).setCusto(cEnlase.getCusto() + vDist.get(key).getCusto());
				myDist.get(key).setId(id);
			}
		}
	}

	public Router getRoteador() {
		return roteador;
	}

	public void setRoteador(Router roteador) {
		this.roteador = roteador;
	}

	public VetorDistancia getVetorDistancia() {
		return vetorDistancia;
	}

	public void setVetorDistancia(VetorDistancia vetorDistancia) {
		this.vetorDistancia = vetorDistancia;
	}

	public void atualizarRotas(int id) {
		System.out.println("disconnected: " + id);
		roteador.setDisconnected(id);
		atualizaVectorRemovido(id);
	}

	private void atualizaVectorRemovido(int idRemoved) {
		vetorDistancia.get(idRemoved).setCusto(TabelaRotas.INFINITY);
		vetorDistancia.get(idRemoved).setId(TabelaRotas.INFINITY);

		for (Integer key : vetorDistancia.getVetor().keySet()) {
			Custo custoVizinho = vetorDistancia.getVetor().get(key);

			if (custoVizinho.getId() == idRemoved) {
				vetorDistancia.get(key).setCusto(TabelaRotas.INFINITY);
				vetorDistancia.get(key).setId(TabelaRotas.INFINITY);

				for (Neighbor no : roteador.getNeighbors()) {
					if (roteador.isConnected(no.getId())) {
						int idVizinho = no.getId();
						int cl = getVectors().get(idVizinho).getVetor().get(idRemoved).getCusto();
						if (vetorDistancia.get(idVizinho).getCusto() + cl <= vetorDistancia.get(idRemoved).getCusto()) {
							vetorDistancia.get(key).setCusto(cl);
							vetorDistancia.get(key).setId(idVizinho);
						}
					}
				}
			}
		}
	}

	public void setVectors(HashMap<Integer, VetorDistancia> vectors) {
		this.vectors = vectors;
	}

	public HashMap<Integer, VetorDistancia> getVectors() {
		return vectors;
	}
}
